/******************************************************************************
 * Copyright (C) 2013 ShenZhen ComTop Information Technology Co.,Ltd
 * All Rights Reserved.
 * 本软件为深圳康拓普开发研制。未经本公司正式书面同意，其他任何个人、团体不得使用、
 * 复制、修改或发布本软件.
 *****************************************************************************/

package com.code.common.util;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

/**
 * 通用的的IO流操纵类
 * 
 * <pre>
 * 提供了针对输入/输出操作的工具方法，提供。 
 * 在源 (<code>InputStream</code>, <code>Reader</code>,<code>String</code> 和 <code>byte[]</code> ) 和目标 ( <code>OutputStream</code>,<code>Writer</code>, <code>String</code> and <code>byte[]</code>)之间使用缓冲区复制.
 * 对于<code>copy</code> 方法, 容许设置一个buffer size，默认为4k.除非另有说明，这些<code>copy</code>方法是不会清空或者关闭流.
 * 对于 字节变换到字符(byte-to-char)的方法, 可设置编码(否则，使用平台默认编码).
 * <code>copy</code> 方法使用内部缓存. 因此没必要再用一次 <code>Buffered*</code> streams包装过的流。
 * </pre>
 * 
 * @author 陈星凌
 * @since TOP4.0
 * @version 2013-1-30 陈星凌 由原TOP系统迁移
 */
public final class IOUtil {
    
    /** 默认缓存大小,单位：字节 */
    private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
    
    /**
     * 私有构造，以防止实例化
     */
    private IOUtil() {
    }
    
    // /////////////////////////////////////////////////////////////
    // 核心复制方法
    // /////////////////////////////////////////////////////////////
    
    /**
     * 复制字节从 <code>InputStream</code> 到 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final OutputStream output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 复制字节从 <code>InputStream</code> 到 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final OutputStream output, final int bufferSize)
        throws IOException {
        final byte[] buffer = new byte[bufferSize];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
    }
    
    /**
     * 复制 chars 从 <code>Reader</code> 到 <code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final Reader input, final Writer output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 复制 chars 从 <code>Reader</code> 到 <code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final Reader input, final Writer output, final int bufferSize) throws IOException {
        final char[] buffer = new char[bufferSize];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        output.flush();
    }
    
    // /////////////////////////////////////////////////////////////
    // 衍生的复制方法
    // InputStream -> *
    // /////////////////////////////////////////////////////////////
    
    // /////////////////////////////////////////////////////////////
    // InputStream -> Writer
    
    /**
     * 复制 同时将<code>InputStream</code>中的字节转化字符的并写到<code>Writer</code>. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final Writer output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 复制 同时将<code>InputStream</code>中的字节转化字符的并写到<code>Writer</code>. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final Writer output, final int bufferSize) throws IOException {
        final InputStreamReader in = new InputStreamReader(input);
        copy(in, output, bufferSize);
    }
    
    /**
     * 复制 同时将<code>InputStream</code>中的字节转化字符的并写到<code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param encoding 编码集.
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final Writer output, final String encoding) throws IOException {
        final InputStreamReader in = new InputStreamReader(input, encoding);
        copy(in, output);
    }
    
    /**
     * 复制 同时将<code>InputStream</code>中的字节转化字符的并写到<code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param encoding 编码集.
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final InputStream input, final Writer output, final String encoding, final int bufferSize)
        throws IOException {
        final InputStreamReader in = new InputStreamReader(input, encoding);
        copy(in, output, bufferSize);
    }
    
    // /////////////////////////////////////////////////////////////
    // InputStream -> String
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final InputStream input) throws IOException {
        return toString(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final InputStream input, final int bufferSize) throws IOException {
        final StringWriter sw = new StringWriter();
        copy(input, sw, bufferSize);
        return sw.toString();
    }
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容.
     * 
     * @param input InputStream
     * @param encoding 编码集.
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final InputStream input, final String encoding) throws IOException {
        return toString(input, encoding, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容.
     * 
     * @param input InputStream
     * @param encoding 编码集.
     * @param bufferSize 内部缓冲值
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final InputStream input, final String encoding, final int bufferSize)
        throws IOException {
        final StringWriter sw = new StringWriter();
        copy(input, sw, encoding, bufferSize);
        return sw.toString();
    }
    
    // /////////////////////////////////////////////////////////////
    // InputStream -> byte[]
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容.
     * 
     * @param input InputStream
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final InputStream input) throws IOException {
        return toByteArray(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>String</code>形式返回从 <code>InputStream</code> 中获取内容.
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final InputStream input, final int bufferSize) throws IOException {
        final ByteArrayOutputStream output = new ByteArrayOutputStream();
        copy(input, output, bufferSize);
        return output.toByteArray();
    }
    
    // /////////////////////////////////////////////////////////////
    // 衍生的复制方法
    // Reader -> *
    // /////////////////////////////////////////////////////////////
    
    // /////////////////////////////////////////////////////////////
    // Reader -> OutputStream
    /**
     * 获取<code>Reader</code>中的字符，以字节方式写到<code>OutputStream</code>, 然后清空 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final Reader input, final OutputStream output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 获取<code>Reader</code>中的字符，以字节方式写到<code>OutputStream</code>, 然后清空 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final Reader input, final OutputStream output, final int bufferSize) throws IOException {
        final OutputStreamWriter out = new OutputStreamWriter(output);
        copy(input, out, bufferSize);
        // 注意: 这里会清空.
        out.flush();
    }
    
    // /////////////////////////////////////////////////////////////
    // Reader -> String
    /**
     * 以<code>String</code>形式返回从 <code>Reader</code> 中获取内容.
     * 
     * @param input InputStream
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final Reader input) throws IOException {
        return toString(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>String</code>形式返回从 <code>Reader</code> 中获取内容.
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final Reader input, final int bufferSize) throws IOException {
        final StringWriter sw = new StringWriter();
        copy(input, sw, bufferSize);
        return sw.toString();
    }
    
    // /////////////////////////////////////////////////////////////
    // Reader -> byte[]
    /**
     * 以<code>byte[]</code>形式返回从 <code>Reader</code> 中获取内容.
     * 
     * @param input InputStream
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final Reader input) throws IOException {
        return toByteArray(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>byte[]</code>形式返回从 <code>Reader</code> 中获取内容.
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final Reader input, final int bufferSize) throws IOException {
        ByteArrayOutputStream objOutput = new ByteArrayOutputStream();
        copy(input, objOutput, bufferSize);
        return objOutput.toByteArray();
    }
    
    // /////////////////////////////////////////////////////////////
    // 衍生的复制方法
    // String -> *
    // /////////////////////////////////////////////////////////////
    
    // /////////////////////////////////////////////////////////////
    // String -> OutputStream
    
    /**
     * 获取<code>String</code>中的字符，以字节方式写到<code>OutputStream</code>, 然后清空 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final String input, final OutputStream output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 获取<code>String</code>中的字符，以字节方式写到<code>OutputStream</code>, 然后清空 <code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final String input, final OutputStream output, final int bufferSize) throws IOException {
        final StringReader in = new StringReader(input);
        final OutputStreamWriter out = new OutputStreamWriter(output);
        copy(in, out, bufferSize);
        // 注意: 这里会清空.
        out.flush();
    }
    
    // /////////////////////////////////////////////////////////////
    // String -> Writer
    
    /**
     * 获取<code>String</code>中的字符，写到<code>Writer</code>中
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final String input, final Writer output) throws IOException {
        output.write(input);
    }
    
    // /////////////////////////////////////////////////////////////
    // String -> byte[]
    /**
     * 以<code>byte[]</code>形式返回 <code>String</code> 中的内容.
     * 
     * @param input InputStream
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final String input) throws IOException {
        return toByteArray(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以<code>byte[]</code>形式返回 <code>String</code> 中的内容.
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return byte
     * @throws IOException IOException
     */
    public static byte[] toByteArray(final String input, final int bufferSize) throws IOException {
        ByteArrayOutputStream objOutput = new ByteArrayOutputStream();
        copy(input, objOutput, bufferSize);
        return objOutput.toByteArray();
    }
    
    // /////////////////////////////////////////////////////////////
    // 衍生的复制方法
    // byte[] -> *
    // /////////////////////////////////////////////////////////////
    
    // /////////////////////////////////////////////////////////////
    // byte[] -> Writer
    
    /**
     * 复制 将<code>byte[]</code>转化字符的并写到<code>Writer</code>. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final Writer output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 复制 将<code>byte[]</code>转化字符的并写到<code>Writer</code>. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final Writer output, final int bufferSize) throws IOException {
        final ByteArrayInputStream in = new ByteArrayInputStream(input);
        copy(in, output, bufferSize);
    }
    
    /**
     * 复制 将<code>byte[]</code>转化字符的并写到<code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param encoding 编码集.
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final Writer output, final String encoding) throws IOException {
        final ByteArrayInputStream in = new ByteArrayInputStream(input);
        copy(in, output, encoding);
    }
    
    /**
     * 复制 将<code>byte[]</code>转化字符的并写到<code>Writer</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param encoding 编码集.
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final Writer output, final String encoding, final int bufferSize)
        throws IOException {
        final ByteArrayInputStream in = new ByteArrayInputStream(input);
        copy(in, output, encoding, bufferSize);
    }
    
    // /////////////////////////////////////////////////////////////
    // byte[] -> String
    
    /**
     * 以String形式返回 <code>byte[]</code> 中的内容. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final byte[] input) throws IOException {
        return toString(input, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以String形式返回 <code>byte[]</code> 中的内容. 使用平台默认编码 (byte-to-char).
     * 
     * @param input InputStream
     * @param bufferSize 内部缓冲值
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final byte[] input, final int bufferSize) throws IOException {
        final StringWriter sw = new StringWriter();
        copy(input, sw, bufferSize);
        return sw.toString();
    }
    
    /**
     * 以String形式返回 <code>byte[]</code> 中的内容.
     * 
     * @param input InputStream
     * @param encoding 编码集.
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final byte[] input, final String encoding) throws IOException {
        return toString(input, encoding, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 以String形式返回 <code>byte[]</code> 中的内容.
     * 
     * @param input InputStream
     * @param encoding 编码集.
     * @param bufferSize 内部缓冲值
     * @return String
     * @throws IOException IOException
     */
    public static String toString(final byte[] input, final String encoding, final int bufferSize) throws IOException {
        final StringWriter sw = new StringWriter();
        copy(input, sw, encoding, bufferSize);
        return sw.toString();
    }
    
    // /////////////////////////////////////////////////////////////
    // byte[] -> OutputStream
    
    /**
     * 复制 从<code>byte[]</code>中获取字节并写到<code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final OutputStream output) throws IOException {
        copy(input, output, DEFAULT_BUFFER_SIZE);
    }
    
    /**
     * 复制 从<code>byte[]</code>中获取字节并写到<code>OutputStream</code>.
     * 
     * @param input InputStream
     * @param output OutputStream
     * @param bufferSize 内部缓冲值
     * @throws IOException IOException
     */
    public static void copy(final byte[] input, final OutputStream output, final int bufferSize) throws IOException {
        output.write(input);
    }
    
    /**
     * 判断两个流中的内容是否相等
     * 
     * @param input1 the first stream
     * @param input2 the second stream
     * @return true 流的内容相等或双方都不存在，否则为false
     * @throws IOException IOException
     */
    public static boolean contentEquals(final InputStream input1, final InputStream input2) throws IOException {
        final InputStream bufferedInput1 = new BufferedInputStream(input1);
        final InputStream bufferedInput2 = new BufferedInputStream(input2);
        
        int iCh = bufferedInput1.read();
        while (-1 != iCh) {
            final int ch2 = bufferedInput2.read();
            if (iCh != ch2) {
                return false;
            }
            iCh = bufferedInput1.read();
        }
        
        final int ch2 = bufferedInput2.read();
        return -1 == ch2;
    }
    
    // ----------------------------------------------------------------------
    // closeQuietlyXXX()
    // ----------------------------------------------------------------------
    
    /**
     * 关闭输入流. 输入流可空，任何IOException的将被忽略。
     * 
     * @param inputStream 要关闭的流.
     */
    public static void closeQuietly(InputStream inputStream) {
        if (inputStream == null) {
            return;
        }
        
        try {
            inputStream.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * 关闭输出流. 输出流可空，任何IOException的将被忽略。
     * 
     * @param outputStream 要关闭的流.
     */
    public static void closeQuietly(OutputStream outputStream) {
        if (outputStream == null) {
            return;
        }
        
        try {
            outputStream.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * 关闭 reader. reader可空，任何IOException的将被忽略。
     * 
     * @param reader 要关闭的reader.
     */
    public static void closeQuietly(Reader reader) {
        if (reader == null) {
            return;
        }
        
        try {
            reader.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    
    /**
     * 关闭 writer. writer可空，任何IOException的将被忽略。
     * 
     * @param writer Writer
     */
    public static void closeQuietly(Writer writer) {
        if (writer == null) {
            return;
        }
        
        try {
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}